import { API_CONFIG } from '../config';
import { ApiResponse, ChainInfo, NodeInfo, Transaction, DIDDocument, DBQueryResult, TransactionProof } from '../types/api';

export class ApiService {
  private static async request<T>(node: keyof typeof API_CONFIG.NODES, endpoint: string, options?: RequestInit): Promise<ApiResponse<T>> {
    const nodeConfig = API_CONFIG.NODES[node];
    
    // Convert node key to lowercase for proxy server
    const nodeType = node.toLowerCase();
    
    // Add node type as query parameter for proxy routing
    const url = new URL(`${nodeConfig.BASE_URL}${endpoint}`);
    url.searchParams.set('node', nodeType);
    
    try {
      const response = await fetch(url.toString(), {
        ...options,
        headers: {
          'Content-Type': 'application/json',
          ...options?.headers,
        },
      });

      // 检查HTTP状态码
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }

      // 尝试解析JSON响应
      const data = await response.json();
      
      // 验证响应格式
      if (typeof data !== 'object' || data === null) {
        throw new Error('Invalid response format: expected object');
      }

      return data as ApiResponse<T>;
    } catch (error) {
      // 如果是网络错误或JSON解析错误，返回标准错误格式
      if (error instanceof TypeError && error.message.includes('fetch')) {
        throw new Error('Network error: Unable to connect to server');
      }
      if (error instanceof SyntaxError) {
        throw new Error('Invalid JSON response from server');
      }
      throw error;
    }
  }

  // 链信息相关API
  static async getChainInfo(node: keyof typeof API_CONFIG.NODES): Promise<ApiResponse<ChainInfo>> {
    return this.request(node, API_CONFIG.ENDPOINTS.CHAIN_INFO);
  }

  static async getNodeCount(node: keyof typeof API_CONFIG.NODES): Promise<ApiResponse<number>> {
    return this.request(node, API_CONFIG.ENDPOINTS.NODE_COUNT);
  }

  static async getCacheTransNumber(node: keyof typeof API_CONFIG.NODES): Promise<ApiResponse<number>> {
    return this.request(node, API_CONFIG.ENDPOINTS.CACHE_TRANS_NUMBER);
  }

  static async getAcceptedTransNumber(node: keyof typeof API_CONFIG.NODES): Promise<ApiResponse<number>> {
    return this.request(node, API_CONFIG.ENDPOINTS.ACCEPTED_TRANS_NUMBER);
  }

  // 交易相关API
  static async postTransaction(node: keyof typeof API_CONFIG.NODES, transaction: any): Promise<ApiResponse<string>> {
    return this.request(node, API_CONFIG.ENDPOINTS.POST_TRANSACTION, {
      method: 'POST',
      body: typeof transaction === 'string' ? transaction : JSON.stringify(transaction),
      headers: {
        'Content-Type': 'application/json',
      },
    });
  }

  static async getTransaction(node: keyof typeof API_CONFIG.NODES, txId: string): Promise<ApiResponse<Transaction>> {
    return this.request(node, `${API_CONFIG.ENDPOINTS.GET_TRANSACTION}/${txId}`);
  }

  static async getTransactionProof(node: keyof typeof API_CONFIG.NODES, txId: string): Promise<ApiResponse<TransactionProof>> {
    return this.request(node, `${API_CONFIG.ENDPOINTS.GET_TRANSACTION_PROOF}/${txId}`);
  }

  // DID相关API
  static async getDIDDocument(node: keyof typeof API_CONFIG.NODES, did: string): Promise<ApiResponse<DIDDocument>> {
    return this.request(node, `${API_CONFIG.ENDPOINTS.GET_DID_DOCUMENT}/${did}`);
  }

  // 数据库相关API
  static async queryDB(node: keyof typeof API_CONFIG.NODES, query: string): Promise<ApiResponse<DBQueryResult>> {
    return this.request(node, API_CONFIG.ENDPOINTS.DB_QUERY, {
      method: 'POST',
      body: JSON.stringify({ query }),
    });
  }

  // 节点信息相关API
  static async getNodeInfo(node: keyof typeof API_CONFIG.NODES): Promise<ApiResponse<NodeInfo>> {
    return this.request(node, API_CONFIG.ENDPOINTS.NODE_INFO);
  }
}

// 兼容旧代码的导出
export const didApi = {
  getDIDDocument: ApiService.getDIDDocument,
  // 这里没有 getDIDPublicKey，DIDSection 需改为本地查找
};

export const transactionApi = {
  postTransaction: ApiService.postTransaction,
  getTransaction: ApiService.getTransaction,
  getTransactionProof: ApiService.getTransactionProof,
}; 